package com.hh.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hh.annotation.AuthCheck;
import com.hh.annotation.Loggable;
import com.hh.common.BaseResponse;
import com.hh.common.DeleteRequest;
import com.hh.common.ErrorCode;
import com.hh.common.ResultUtils;
import com.hh.constant.UserConstant;
import com.hh.entity.domain.ArticleTagCategory;
import com.hh.entity.domain.Blog;
import com.hh.entity.domain.User;
import com.hh.entity.domain.UserCollection;
import com.hh.entity.dto.blog.BlogAddRequest;
import com.hh.entity.dto.blog.BlogQueryRequest;
import com.hh.entity.dto.blog.BlogReviewRequest;
import com.hh.entity.dto.blog.BlogUpdateRequest;
import com.hh.entity.enums.ArticleReviewStatusEnum;
import com.hh.entity.vo.BlogVO;
import com.hh.exception.BusinessException;
import com.hh.exception.ThrowUtils;
import com.hh.service.BlogService;
import com.hh.service.ThumbService;
import com.hh.service.UserCollectionService;
import com.hh.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * springboot-template
 *
 * @author hanhui
 * @version 0.0.1
 * @description 博客控制器，提供文章的增删改查、收藏、审核等功能
 **/
@RestController
@Slf4j
@RequestMapping("/blog")
public class BlogController {
    /**
     * 博客服务接口
     */
    @Resource
    private BlogService blogService;

    /**
     * 用户服务接口
     */
    @Resource
    private UserService userService;

    /**
     * 点赞服务接口
     */
    @Resource
    ThumbService thumbService;

    /**
     * 用户收藏服务接口
     */
    @Resource
    UserCollectionService userCollectionService;

    /**
     * Redis模板对象，用于缓存操作
     */
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 添加文章
     *
     * @param blogAddRequest 文章添加请求对象，包含文章标题、内容等信息
     * @param request        HTTP请求对象，用于获取登录用户信息
     * @return BaseResponse<Long> 添加结果，包含文章ID
     */
    @PostMapping("/add")
    public BaseResponse<Long> addBlog(
            @RequestBody BlogAddRequest blogAddRequest,
            HttpServletRequest request) {

        User loginUser = userService.getLoginUser(request);
        Blog blog = blogService.addBlog(blogAddRequest, loginUser);
        return ResultUtils.success(blog.getId());
    }

    /**
     * 删除文章
     *
     * @param deleteRequest 文章删除请求对象，包含文章ID信息
     * @param request       HTTP请求对象，用于获取登录用户信息
     * @return BaseResponse<Boolean> 删除结果
     */
    @PostMapping("/delete")
    public BaseResponse<Boolean> deleteBlog(
            @RequestBody DeleteRequest deleteRequest,
            HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        Boolean success = blogService.deleteBlog(deleteRequest, loginUser);
        return ResultUtils.success(success);
    }

    /**
     * 更新文章
     *
     * @param blogUpdateRequest 文章更新请求对象，包含文章ID和更新内容
     * @param request           HTTP请求对象，用于获取登录用户信息
     * @return BaseResponse<Boolean> 更新结果
     */
    @PostMapping("/update")
    public BaseResponse<Boolean> updateBlog(
            @RequestBody BlogUpdateRequest blogUpdateRequest,
            HttpServletRequest request) {
        // 获取登录用户
        User loginUser = userService.getLoginUser(request);
        // 更新文章
        blogService.updateBlog(blogUpdateRequest, loginUser);
        // 返回更新结果
        return ResultUtils.success(true);
    }

    /**
     * 根据ID查询文章（管理员专用）
     * 只有管理员可以访问此接口，用于查看所有文章的详细信息
     *
     * @param id 文章ID
     * @return BaseResponse<Blog> 文章对象
     */
    @PostMapping("/get/blog")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Blog> getBlogById(@RequestBody Long id) {
        // 记录日志
        log.info("Getting Blog with ID: {}", id);
        // 根据ID查询文章
        Blog blog = blogService.getById(id);
        // 如果文章存在，则返回成功
        if (blog != null) {
            return ResultUtils.success(blog);
        } else {
            // 如果文章不存在，则抛出异常
            throw new BusinessException(ErrorCode.FILE_NOT_FOUND);
        }
    }

    /**
     * 根据ID查询文章（普通用户）
     * 普通用户只能查看已审核通过的文章
     *
     * @param id      文章ID
     * @param request HTTP请求对象，用于获取登录用户信息
     * @return BaseResponse<BlogVO> 文章视图对象，包含文章详细信息
     */
    @Loggable
    @GetMapping("/get/{id}")
    public BaseResponse<BlogVO> getBlogById(@PathVariable Long id, HttpServletRequest request) {
        // 记录日志
        log.info("Getting Blog with ID: {}", id);
        // 获取登录用户
        User loginUser = userService.getLoginUser(request);
        // 根据ID查询文章
        Blog blog = blogService.lambdaQuery().eq(Blog::getId, id)
                .eq(Blog::getReviewStatus, ArticleReviewStatusEnum.PASS.getValue())
                .one();
        // 将文章转换为VO对象
        BlogVO blogVo = blogService.getBlogVo(blog);
        // 如果文章不存在，抛出异常
        if (blogVo == null) {
            throw new BusinessException(ErrorCode.FILE_NOT_FOUND);
        }
        Boolean hasThumb = thumbService.hasThumb(id, loginUser.getId());
        blogVo.setHasThumb(hasThumb);
        // 返回成功结果
        return ResultUtils.success(blogVo);
    }

    /**
     * 分页查询文章（管理员专用）
     * 只有管理员可以访问此接口，用于查看所有文章的分页列表
     *
     * @param blogQueryRequest 文章查询请求对象，包含分页参数和查询条件
     * @return BaseResponse<Page < Blog>> 文章列表
     */
    @GetMapping("/list/page")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Page<Blog>> listBlogByPage(BlogQueryRequest blogQueryRequest) {
        // 判断查询请求是否为空，如果为空则抛出异常
        ThrowUtils.throwIf(blogQueryRequest == null, ErrorCode.PARAMS_NULL);
        // 获取查询请求中的每页大小
        int pageSize = blogQueryRequest.getPageSize();
        // 获取查询请求中的页码
        int pageNum = blogQueryRequest.getPageNum();
        // 调用blogService的page方法，传入分页参数和查询条件，获取文章分页结果
        Page<Blog> BlogPage = blogService.page(new Page<>(pageNum, pageSize),
                blogService.getQueryWrapper(blogQueryRequest));
        // 打印文章分页结果
        log.info("Blog:{}", BlogPage);
        List<Blog> blogList = BlogPage.getRecords();
        Page<Blog> BlogPageList = new Page<>(BlogPage.getCurrent(), BlogPage.getSize(), BlogPage.getTotal());
        BlogPageList.setRecords(blogList);
        // 返回文章分页结果
        return ResultUtils.success(BlogPageList);
    }

    /**
     * 分页查询文章（普通用户）
     * 普通用户只能查看已审核通过的文章
     *
     * @param blogQueryRequest 文章查询请求对象，包含分页参数和查询条件
     * @param request          HTTP请求对象，用于获取登录用户信息
     * @return BaseResponse<Page < BlogVO>> 文章视图对象列表
     */
    @Loggable
    @PostMapping("/list/page/vo")
    public BaseResponse<Page<BlogVO>> listBlogVOByPage(@RequestBody BlogQueryRequest blogQueryRequest, HttpServletRequest request) {
        // 判断查询请求是否为空
        ThrowUtils.throwIf(blogQueryRequest == null, ErrorCode.PARAMS_NULL);
        // 获取每页大小
        int pageSize = blogQueryRequest.getPageSize();
        // 获取当前页码
        int pageNum = blogQueryRequest.getPageNum();
        //防爬虫
        ThrowUtils.throwIf(pageNum > 10, ErrorCode.PARAMS_ERROR);
        // 打印查询请求
        log.info(String.valueOf(blogQueryRequest));
        // 设置查询状态为已通过
        blogQueryRequest.setReviewStatus(ArticleReviewStatusEnum.PASS.getValue());
        // 分页查询文章
        Page<Blog> BlogPage = blogService.page(new Page<>(pageNum, pageSize),
                blogService.getQueryWrapper(blogQueryRequest));
        // 返回文章列表
        return ResultUtils.success(blogService.getBlogVoPage(BlogPage, request));
    }

    /**
     * 查询我的收藏文章
     * 获取当前用户收藏的文章列表
     *
     * @param blogQueryRequest 查询请求对象，包含分页参数
     * @param request          HTTP请求对象，用于获取登录用户信息
     * @return BaseResponse<Page < BlogVO>> 收藏的文章视图对象列表
     */
    @Loggable
    @GetMapping("/list/page/vo/my")
    public BaseResponse<Page<BlogVO>> listMyCollection(BlogQueryRequest blogQueryRequest, HttpServletRequest request) {
        // 判断查询请求是否为空
        ThrowUtils.throwIf(blogQueryRequest == null, ErrorCode.PARAMS_NULL);
        // 获取每页大小
        int pageSize = blogQueryRequest.getPageSize();
        // 获取当前页码
        int pageNum = blogQueryRequest.getPageNum();
        // 获取登录用户
        User loginUser = userService.getLoginUser(request);
        // 设置查询状态为已通过
        blogQueryRequest.setReviewStatus(ArticleReviewStatusEnum.PASS.getValue());
        // 分页查询文章
        // 我收藏的文章
        List<UserCollection> collectionList = userCollectionService.list(new QueryWrapper<UserCollection>().eq("userId", loginUser.getId()));

        // 添加判空逻辑
        if (collectionList == null || collectionList.isEmpty()) {
            // 如果收藏列表为空，返回空的分页结果
            Page<Blog> emptyBlogPage = new Page<>(pageNum, pageSize);
            emptyBlogPage.setRecords(Collections.emptyList());
            emptyBlogPage.setTotal(0);
            return ResultUtils.success(blogService.getBlogVoPage(emptyBlogPage, request));
        }

        // 获取文章ID集合
        List<Long> blogIds = collectionList.stream().map(UserCollection::getBlogId).collect(Collectors.toList());
        // 添加对blogIds的判空检查
        if (blogIds.isEmpty()) {
            // 如果没有有效的文章ID，返回空的分页结果
            Page<Blog> emptyBlogPage = new Page<>(pageNum, pageSize);
            emptyBlogPage.setRecords(Collections.emptyList());
            emptyBlogPage.setTotal(0);
            return ResultUtils.success(blogService.getBlogVoPage(emptyBlogPage, request));
        }

        List<Blog> blogList = blogService.listByIds(blogIds);

        // 添加对blogList的判空检查
        if (blogList == null) {
            blogList = new ArrayList<>();
        }

        Page<Blog> BlogPage = new Page<>(pageNum, pageSize);
        BlogPage.setRecords(blogList);
        BlogPage.setTotal(blogList.size());

        // 返回文章列表
        return ResultUtils.success(blogService.getBlogVoPage(BlogPage, request));
    }

    /**
     * 分页查询文章（带缓存）
     * 使用Redis缓存查询结果，提高性能
     *
     * @param blogQueryRequest 查询请求对象，包含分页参数
     * @param request          HTTP请求对象，用于获取登录用户信息
     * @return BaseResponse<Page < BlogVO>> 文章视图对象列表
     */
    @GetMapping("/list/page/vo/cache")
    public BaseResponse<Page<BlogVO>> listBlogVOByCache(BlogQueryRequest blogQueryRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(blogQueryRequest == null, ErrorCode.PARAMS_NULL);

        int pageSize = blogQueryRequest.getPageSize();
        int pageNum = blogQueryRequest.getPageNum();
        Integer reviewStatus = ArticleReviewStatusEnum.PASS.getValue();
        String cacheKey = String.format("blog:list:page:vo:%d:%d", pageNum, pageSize);
        // 1. 从 Redis 获取缓存数据
        Page<BlogVO> cachedData = (Page<BlogVO>) redisTemplate.opsForValue().get(cacheKey);
        if (cachedData != null) {
            return ResultUtils.success(cachedData);
        }
        // 2. 缓存未命中，查询数据库
        blogQueryRequest.setReviewStatus(reviewStatus);
        Page<Blog> BlogPage = blogService.page(new Page<>(pageNum, pageSize),
                blogService.getQueryWrapper(blogQueryRequest));

        Page<BlogVO> voPage = blogService.getBlogVoPage(BlogPage, request);

        // 3. 将结果写入 Redis 缓存，设置过期时间（如 5 分钟）
        redisTemplate.opsForValue().set(cacheKey, voPage, 5, TimeUnit.MINUTES);
        return ResultUtils.success(voPage);
    }

    //    @AuthCheck
    @PostMapping("/list/page/es")
    public BaseResponse<Page<BlogVO>> listPageByEs(@RequestBody BlogQueryRequest blogQueryRequest) {
        Page<BlogVO> blogPage = blogService.searchFromEs(blogQueryRequest);
        return ResultUtils.success(blogPage);
    }

    /**
     * 获取文章标签分类
     * 返回系统支持的文章标签和分类列表
     *
     * @return BaseResponse<ArticleTagCategory> 标签分类对象，包含标签列表和分类列表
     */
    @Loggable
    @GetMapping("/tag_category")
    // 返回文章标签分类
    public BaseResponse<ArticleTagCategory> listPictureTagCategory() {
        // 创建文章标签分类对象
        ArticleTagCategory pictureTagCategory = new ArticleTagCategory();
        // 创建标签列表
        List<String> tagList = Arrays.asList("java", "c++", "SpringBoot", "数据结构", "校园", "创意");
        // 创建分类列表
        List<String> categoryList = Arrays.asList("生活", "娱乐", "技术", "资讯", "其他");
        // 设置标签列表
        pictureTagCategory.setTagList(tagList);
        // 设置分类列表
        pictureTagCategory.setCategoryList(categoryList);
        // 返回成功结果
        return ResultUtils.success(pictureTagCategory);
    }

    /**
     * 获取热门文章排行榜
     * 根据浏览量等指标获取热门文章列表
     *
     * @param limit 返回的文章数量，默认为10
     * @return BaseResponse<List < BlogVO>> 文章VO列表
     */
    @GetMapping("/hot")
    public BaseResponse<List<BlogVO>> getHotBlogs(@RequestParam(defaultValue = "10") int limit) {
        // 调用blogService的getHotBlogs方法，获取热门文章列表
        return ResultUtils.success(blogService.getHotBlogs(limit));
    }

    /**
     * 管理员审核文章
     * 只有管理员可以访问此接口，用于审核文章
     *
     * @param blogReviewRequest 博客审核请求对象，包含文章ID和审核结果
     * @param request           HTTP请求对象，用于获取登录用户信息
     * @return BaseResponse<Boolean> 审核结果
     */
    @PostMapping("/review")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> doPictureReview(@RequestBody BlogReviewRequest blogReviewRequest,
                                                 HttpServletRequest request) {
        // 抛出异常，如果blogReviewRequest为空
        ThrowUtils.throwIf(blogReviewRequest == null, ErrorCode.PARAMS_ERROR);
        // 获取登录用户
        User loginUser = userService.getLoginUser(request);
        // 进行博客审核
        blogService.doBlogReview(blogReviewRequest, loginUser);
        // 返回成功结果
        return ResultUtils.success(true);
    }

    /**
     * 获取文章标签云
     * 返回所有文章标签及其使用次数的统计信息
     *
     * @return BaseResponse<Map < String, Integer>> 标签及其使用次数的映射
     */
    @GetMapping("/tabCloud")
    public BaseResponse<Map<String, Integer>> getTabCloud() {

        return ResultUtils.success(blogService.getTabCloud());
    }
}
